using System.Collections.Concurrent;

namespace Pinwheel.Kernel
{
    public class MessageQueue : IMessageQueue<ServiceMessage>
    {
        private readonly ConcurrentQueue<ServiceMessage> m_Queue = new ConcurrentQueue<ServiceMessage>();
        
        public int Count => m_Queue.Count;
        public int State = 0;
        
        protected IService m_Service;
        public IService Service => m_Service;
        
        public MessageQueue(IService service)
        {
            m_Service = service;
        }
        
        public void Enqueue(ServiceMessage message)
        {
            m_Queue.Enqueue(message);
            var origin = Interlocked.CompareExchange(ref State, 1, 0);
            if (0 == origin) Global.MessageQueues.Enqueue(this);
        }

        public bool TryPeek(out ServiceMessage message)
        {
            return m_Queue.TryPeek(out message);
        }

        public bool TryDequeue(out ServiceMessage message)
        {
            return m_Queue.TryDequeue(out message);
        }
        
        public async ValueTask<IMessage> DispatchAsync()
        {
            if (TryDequeue(out var message))
            {
                Interlocked.Increment(ref State);
                var result = await Service.ReceiveAsync(message);
                Interlocked.Decrement(ref State);
                if (0 == m_Queue.Count) Interlocked.CompareExchange(ref State, 0, 1);
                return result;
            }
            return null!;
        }
    }
}